package com.tongji.diy.model
{
	import com.tongji.diy.event.FurnitureAdjustIntersectEvent;
	import com.tongji.diy.event.FurnitureLocationAndRotation;
	import com.tongji.diy.event.FurnitureOverlapEvent;
	import com.tongji.diy.event.FurnitureRotationEvent;
	import com.tongji.diy.utils.PolygonMath;
	import com.tongji.diy.utils.RoomParameters;
	
	import de.polygonal.ds.DListNode;
	
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	
	import org.robotlegs.mvcs.Actor;
	
	[Bindable]
	public class FurnitureModel extends Actor
	{

		[Inject]
		public var roomModel:RoomDataModel;
		private var squreRWall:Number = RoomParameters.wallWidth*RoomParameters.wallWidth;
		private var rotateTempAngle:Number = 0;
		private var rotateTempLocation:Point = new Point();
		private var rotateTempEPA:Point = new Point();
		private var rotateTempEPB:Point = new Point();
		private var tempMouseLocation:Point = new Point();
		private var tempFinalAngle:Number = 0;
		//currentFurnitureindex
		private var _CFIndex:uint;
		//currentFurniture
		private var _CF:FurnitureDataVO;
		
		private var furnitureVector:Vector.<FurnitureDataVO> = new Vector.<FurnitureDataVO>;

		public function FurnitureModel()
		{
			super();
		}
		
		public function set CF(currentFurnitureIndex:uint):void
		{
			_CFIndex = currentFurnitureIndex;
			_CF = furnitureVector[_CFIndex];
		}
		
		public function furnitureFinalState(position:Vector3D, angle:Number, parentIndex:uint):void
		{
			_CF.x = position.x + roomModel.rooms[parentIndex].x;
			_CF.y = position.y + roomModel.rooms[parentIndex].y;
			_CF.z = position.z;
			_CF.rotation = angle;
			_CF.parentIndex = parentIndex;
		}
		
		public function addFurniture(index:uint, position:Point, angle:Number, length:Number, width:Number, height:Number, furnitureClass:int):void
		{

			var tempVO:FurnitureDataVO = new FurnitureDataVO(index,length,width,height, furnitureClass);
			tempVO.x = position.x;
			tempVO.y = position.y;
			tempVO.rotation = angle;
			furnitureVector.push(tempVO);
			_CFIndex = tempVO.furnitureIndex;
			_CF = tempVO;
		}
		
		public function furnitureRotation(e:FurnitureRotationEvent):void
		{
			if(e.currentParentIsRoom)
			{
				e.furnitureLocation = e.furnitureLocation.add(new Point(roomModel.rooms[e.parentRoomIndex].x,roomModel.rooms[e.parentRoomIndex].y));
			}
			var finalAngle:Number = _CF.rotation;
			var overlapAngle:Number = e.rotatedAngle;
			var finalLocation:Point = e.furnitureLocation;
			var RVO:RoomDataVO = roomModel.rooms[e.parentRoomIndex];
			var H:DListNode = RVO.roomPointList.head;
			
			var edgePAV:Vector.<Point> = new Vector.<Point>;//旋转前计算相交的直线个数
			var edgePBV:Vector.<Point> = new Vector.<Point>;
			var edgePAV2:Vector.<Point> = new Vector.<Point>;//旋转后
			var edgePBV2:Vector.<Point> = new Vector.<Point>;
			var OBB:Vector.<Point> = buildOBB(e.furnitureLocation, e.width,e.length, finalAngle/180*Math.PI);
			var backVector:Point = OBB[1].subtract(OBB[0]);			
			
			var rotate:Boolean = false;
			var rotateEdgeVector:Point;
			var tempLocation:Point = e.furnitureLocation;
			var tempAngle:Number = 0;
			var overlap:Boolean = false;
			var pedal:Point;
			var delt:Point;
			H = RVO.roomPointList.head;
			var keep:Boolean = false;
			//该循环判断家具模型与哪一个房间的墙相交，将相交的墙的信息存储在edgePAV，edgePBV中（edgePAV，edgePBV中的边的信息没有重复值）
			while(1)
			{
				var LA:Point = new Point(H.data.globalX, H.data.globalY);
				var LB:Point = new Point(H.next.data.globalX, H.next.data.globalY);
				for(var i:int = 0;i<OBB.length;i++)
				{
					if(PolygonMath.pointToLineSquareDistance(LA,LB,OBB[i]) <= squreRWall || PolygonMath.edgeIntersect(LA, LB, OBB[i], OBB[(i+1) % OBB.length],true))
					{
						rotate = true;
						var addNew:Boolean = true;
						for(var j:int = 0;j < edgePAV.length; j++)
						{
							if(edgePAV[j] == LA||edgePBV[j] == LB)
							{
								addNew = false;
								break;
							}
						}
						if(addNew)
						{
							edgePAV.push(LA);		
							edgePBV.push(LB);
						}
					}
				}
				H = H.next;
				if(H == RVO.roomPointList.head)
					break;
			}
			//keep变量给出前一次帧旋转参考的墙与当前帧的旋转墙的关系，如果keep为真则按照前一帧旋转的墙作为当前帧的旋转墙
			//否则则根据edgePAV，edgePBV中的第一个碰撞边作为旋转墙的参考边
			for(i = 0;i < edgePAV.length; i++)
			{
				if(edgePAV[i].equals(rotateTempEPA)&& edgePBV[i].equals(rotateTempEPB))
				{
					keep = true;
					break;
				}
			}
			if(keep && rotate)
			{
				LA = rotateTempEPA;
				LB = rotateTempEPB;
				pedal = PolygonMath.pedal(LA,LB,e.furnitureLocation);
				delt = e.furnitureLocation.subtract(pedal);
				tempLocation = new Point(e.length/2/delt.length*delt.x + pedal.x + RoomParameters.wallWidth/delt.length * delt.x, e.length/2/delt.length*delt.y + pedal.y + RoomParameters.wallWidth/delt.length * delt.y);
				rotateEdgeVector = LB.subtract(LA);				
			}
			else if(rotate)
			{
				rotateTempEPA = edgePAV[0];
				rotateTempEPB = edgePBV[0];
				pedal = PolygonMath.pedal(edgePAV[0],edgePBV[0],e.furnitureLocation);
				delt = e.furnitureLocation.subtract(pedal);
				tempLocation = new Point(e.length/2/delt.length*delt.x + pedal.x + RoomParameters.wallWidth/delt.length * delt.x, e.length/2/delt.length*delt.y + pedal.y + RoomParameters.wallWidth/delt.length * delt.y);
				rotateEdgeVector = edgePBV[0].subtract(edgePAV[0]);
			}
			//旋转角度计算
			if(rotate)
			{
				if(rotateEdgeVector.x*backVector.y - backVector.x*rotateEdgeVector.y > 0)
				{
					tempAngle = PolygonMath.vectorAngle(rotateEdgeVector, backVector);
				}
				else
				{
					tempAngle = -PolygonMath.vectorAngle(rotateEdgeVector, backVector);
				}
			}
			//旋转后是否相交计算
			if(rotate)
			{
				var OBB2:Vector.<Point> = buildOBB(tempLocation, e.width, e.length, tempAngle+finalAngle*Math.PI/180);
				H = RVO.roomPointList.head;
				while(!overlap)
				{
					LA = new Point(H.data.globalX, H.data.globalY);
					LB = new Point(H.next.data.globalX, H.next.data.globalY);
					for(i = 0;i<OBB2.length;i++)
					{						
						if(PolygonMath.pointToLineSquareDistance(LA,LB,OBB2[i])+1 <= squreRWall || PolygonMath.edgeIntersect(LA, LB, OBB2[i], OBB2[(i+1)%OBB2.length]))
						{
							overlap = true;
							var addNew2:Boolean = true;
							for(j = 0;j < edgePAV2.length; j++)
							{
								if(edgePAV2[j] == LA||edgePBV2[j] == LB)
								{
									addNew = false;
									break;
								}
							}
							if(addNew2)
							{
								edgePAV2.push(LA);		
								edgePBV2.push(LB);
							}
						}
					}
					H = H.next;
					if(H == RVO.roomPointList.head)
						break;
				}
			}
			if(rotate && !overlap)
			{
				finalLocation = tempLocation;
				tempMouseLocation = tempLocation;
				finalAngle += tempAngle*180/Math.PI;
				overlapAngle += tempAngle*180/Math.PI;
				tempFinalAngle = finalAngle;
			}
			else if(rotate && overlap && (edgePAV.length > 1 || edgePAV2.length > 0))
			{	
				finalLocation = tempMouseLocation;
				/*finalAngle = _CF.rotation;
				overlapAngle = _CF.rotation;*/
				finalAngle = tempFinalAngle;
				overlapAngle = tempFinalAngle;
			}
			else
			{
				tempMouseLocation = e.furnitureLocation;
				finalAngle += tempAngle*180/Math.PI;
				overlapAngle += tempAngle*180/Math.PI;
				tempFinalAngle = finalAngle;
			}
			var currentLocation:Point = new Point;
			if(e.currentParentIsRoom)
			{
				finalLocation = finalLocation.subtract(new Point(roomModel.rooms[e.parentRoomIndex].x,roomModel.rooms[e.parentRoomIndex].y));
				currentLocation.x = finalLocation.x + roomModel.rooms[e.parentRoomIndex].x;
				currentLocation.y = finalLocation.y + roomModel.rooms[e.parentRoomIndex].y;
			}
			else
			{
				currentLocation.x = finalLocation.x ;
				currentLocation.y = finalLocation.y ;
			}
			//以下内容是不同等级家具之间相互拖拽产生的，例如电视机（等级2）拖拽到桌子上（等级1），电视机将会位于桌子之上
			//但是相同等级之间将满足相互不想交规则。
			var furnitureOverlapObject:FurnitureOverlapReturnData = furnitureOverlap(furnitureVector[e.furnitureIndex],currentLocation,overlapAngle);		
			var finalLocation3D:Vector3D = new Vector3D(finalLocation.x, finalLocation.y);
			
			finalLocation3D.z = furnitureZLocation(furnitureVector[e.furnitureIndex], furnitureOverlapObject);
			dispatch(new FurnitureOverlapEvent(FurnitureOverlapEvent.FURNITURE_OVERLAP, furnitureOverlapObject.collisionSign));
			dispatch(new FurnitureAdjustIntersectEvent(FurnitureAdjustIntersectEvent.FURNITURE_INTERSECT,overlap));
			dispatch(new FurnitureLocationAndRotation(FurnitureLocationAndRotation.SET_FURNITURE_LOCATION_AND_ROTATION,finalLocation3D, finalAngle));
			//test
			//dispatch(new TestBoundBoxEvent(TestBoundBoxEvent.TEST_BOUND,new Point(_CF.x, _CF.y), _CF.furnitureWidth, _CF.furnitureLength,finalAngle));
			
		}
		//获得家具拖动过程中的Z坐标值
		private function furnitureZLocation(furniture:FurnitureDataVO, furnitureOverlapObject:FurnitureOverlapReturnData):int
		{
			var result:int = 0;
			if(furnitureOverlapObject.collisionFurnitureIndex >= 0 && furnitureVector[furnitureOverlapObject.collisionFurnitureIndex] && furniture.furnitureLayer >= furnitureVector[furnitureOverlapObject.collisionFurnitureIndex].furnitureLayer)
			{
				result = furnitureVector[furnitureOverlapObject.collisionFurnitureIndex].z;
			}
			
			if(furnitureOverlapObject.parentFurnitureIndex >= 0 && furnitureVector[furnitureOverlapObject.parentFurnitureIndex] && furniture.furnitureLayer >= furnitureVector[furnitureOverlapObject.parentFurnitureIndex].furnitureLayer)
			{
				result = furnitureVector[furnitureOverlapObject.parentFurnitureIndex].furnitureHeight;
			}
			
			//如果是吊灯的将放置到屋顶上
			if(furniture.furnitureLayer == 3)
				result = RoomParameters.wallHeight - furniture.furnitureHeight;
			
			return result;
		}
		
		private function furnitureOverlap(testFurniture:FurnitureDataVO, currentLocation:Point,overlapAngle:Number):FurnitureOverlapReturnData
		{
			var collisionSign:Boolean = false;
			var result:FurnitureOverlapReturnData = new FurnitureOverlapReturnData(-1,-1,false);
			var parent:FurnitureDataVO;
			var collisionObject:FurnitureDataVO;
			var testOBB:Vector.<Point> = buildOBB(currentLocation/*new Point(testFurniture.x,testFurniture.y)*/,testFurniture.furnitureWidth, testFurniture.furnitureLength, overlapAngle*Math.PI/180);
			for(var i:int = 0; i < furnitureVector.length; i++)
			{
				if(furnitureVector[i] != testFurniture)
				{									
					var objectVO:FurnitureDataVO = furnitureVector[i];
					var location:Point = new Point(objectVO.x ,objectVO.y);
					var objectOBB:Vector.<Point> = buildOBB(location, objectVO.furnitureWidth, objectVO.furnitureLength, objectVO.rotation*Math.PI/180);
					collisionSign = PolygonMath.rectangleSeparatingAxisCollisionTest(objectOBB,testOBB) == -1;
					if(collisionSign && testFurniture.furnitureLayer > objectVO.furnitureLayer)
					{
						if(parent == null)
						{
							parent = objectVO;
						}							
						else
							trace("parent object > 1");
					}
					else if(testFurniture.furnitureLayer == objectVO.furnitureLayer && collisionSign)
					{
						collisionObject = objectVO;
						result.collisionSign = true;
						break;
					}
				}
			}
	
			if(parent)
				result.parentFurnitureIndex = parent.furnitureIndex;
			if(collisionObject)
				result.collisionFurnitureIndex = collisionObject.furnitureIndex;
			
			return result;			
		}
		
		private function buildOBB(location:Point, width:Number, length:Number, angle:Number):Vector.<Point>
		{
			var AABB:Vector.<Point> = new Vector.<Point>;
			var leftTop:Point = new Point(location.x - width/2, location.y + length/2);
			AABB.push(leftTop);
			var rightTop:Point = new Point(location.x + width/2, location.y + length/2);
			AABB.push(rightTop);
			var rightBottom:Point = new Point(location.x + width/2, location.y - length/2);
			AABB.push(rightBottom);
			var leftBottom:Point = new Point(location.x - width/2, location.y - length/2);
			AABB.push(leftBottom);
			
			var moveM1:Matrix = new Matrix();
			moveM1.translate(-location.x, -location.y);
			var moveM2:Matrix = new Matrix();
			moveM2.translate(location.x, location.y);
			var rotateM:Matrix = new Matrix();
			rotateM.rotate(-angle);
			moveM1.concat(rotateM);
			moveM1.concat(moveM2);
			var transM:Matrix = moveM1;
			
			for(var i:int = 0;i<AABB.length;i++)
			{
				AABB[i] = transM.transformPoint(AABB[i]);
			}
			
			return AABB;
			
		}
		public function furnitureMaunalRotation(furnitureIndex:uint, clockwise:Boolean):void
		{
			var angle:Number = -3;
			if(!clockwise)
				angle = -angle;
			var tempFurniture:FurnitureDataVO = furnitureVector[furnitureIndex];
			tempFurniture.rotation += angle;
			var location:Vector3D = new Vector3D(tempFurniture.x,tempFurniture.y, tempFurniture.z).subtract(new Vector3D(roomModel.rooms[tempFurniture.parentIndex].x,roomModel.rooms[tempFurniture.parentIndex].y,0));
			dispatch(new FurnitureLocationAndRotation(FurnitureLocationAndRotation.SET_FURNITURE_LOCATION_AND_ROTATION, location,furnitureVector[furnitureIndex].rotation));
		}
	}
}